/*
 * Copyright (c)  2008 Sebastien Tremblay
 *
 * id3-tag-builder - classes.id3.JAudioTaggerProxy.java
 *
 * All source and documentation is copyrighted by Sebastien Tremblay
 * (seb at ryders dot net) and made available under the Apache License 2.0.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * $Id: JAudioTaggerProxy.java 30 2010-01-08 04:01:06Z ryders $
 */
package com.empireone.id3tagbuilder.classes.id3;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.CannotWriteException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.FieldDataInvalidException;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.id3.AbstractID3v2Frame;
import org.jaudiotagger.tag.id3.ID3v11Tag;
import org.jaudiotagger.tag.id3.ID3v24Frame;
import org.jaudiotagger.tag.id3.ID3v24Frames;
import org.jaudiotagger.tag.id3.ID3v24Tag;
import org.jaudiotagger.tag.id3.framebody.AbstractFrameBodyTextInfo;

/**
 * The <code>JAudioTaggerProxy</code> class is the id3 proxy interface to the
 * JAudioTagger library by Paul Taylor - http://www.jthink.net/jaudiotagger/
 *
 * Currently supports Mp4 (Mp4, M4p, M4a), Mp3 (id3v1,id3v2) and Ogg Vorbis
 *
 * @author Sebastien Tremblay
 */
public class JAudioTaggerProxy implements Id3Proxy {

    private File file;
    private MP3File mp3;
    private ID3Version vers;
    private ID3v11Tag id3v1;
    private ID3v24Tag id3v2;

    @Override
    public void init(File file, ID3Version v) throws Id3ProxyException {

        this.file = file;
        this.vers = v;
        try {
            this.mp3 = (MP3File) AudioFileIO.read(file);
        } catch (CannotReadException ex) {
            throw new Id3ProxyException("File cannot be read - " + file.getPath());
        } catch (IOException ex) {
            throw new Id3ProxyException("File cannot be updated (is it benig used?) - " + file.getPath());
        } catch (TagException ex) {
            throw new Id3ProxyException("Tag corrupted? @todo - " + file.getPath());
        } catch (ReadOnlyFileException ex) {
            throw new Id3ProxyException("File cannot be written - " + file.getPath());
        } catch (InvalidAudioFrameException ex) {
            throw new Id3ProxyException("Frame Corrupted? @todo - " + file.getPath());
        }

        try {
            id3v1 = (ID3v11Tag) mp3.getID3v1Tag();
        } catch (ClassCastException ex) {
            id3v1 = new ID3v11Tag();
        }

        id3v2 = (ID3v24Tag) mp3.getID3v2TagAsv24();

    }

    @Override
    public void cleanAllTags() {
        this.id3v1 = new ID3v11Tag();
        this.id3v2 = new ID3v24Tag();
    }

    @Override
    public void setTitle(String value) throws Id3ProxyDataException {
        if (this.vers == ID3Version.V1 || this.vers == ID3Version.ALL) {
            this.id3v1.setTitle(value);
        }
        if (this.vers == ID3Version.V2 || this.vers == ID3Version.ALL) {
            try {
                this.id3v2.setTitle(value);
            } catch (FieldDataInvalidException ex) {
                throw new Id3ProxyDataException();
            }
        }
    }

    @Override
    public void setTrackNo(String value) throws Id3ProxyUnsupportedException, Id3ProxyDataException {
        if (this.vers == ID3Version.V1 || this.vers == ID3Version.ALL) {
            this.id3v1.setTrack(value);
        }
        if (this.vers == ID3Version.V2 || this.vers == ID3Version.ALL) {
            try {
                this.id3v2.setTrack(value);
            } catch (FieldDataInvalidException ex) {
                throw new Id3ProxyDataException();
            }
        }
    }

    @Override
    public void setArtist(String value) throws Id3ProxyDataException {
        if (this.vers == ID3Version.V1 || this.vers == ID3Version.ALL) {
            this.id3v1.setArtist(value);
        }
        if (this.vers == ID3Version.V2 || this.vers == ID3Version.ALL) {
            try {
                this.id3v2.setArtist(value);
            } catch (FieldDataInvalidException ex) {
                throw new Id3ProxyDataException();
            }
        }
    }

    @Override
    public void setAlbum(String value) throws Id3ProxyDataException {
        if (this.vers == ID3Version.V1 || this.vers == ID3Version.ALL) {
            this.id3v1.setAlbum(value);
        }
        if (this.vers == ID3Version.V2 || this.vers == ID3Version.ALL) {
            try {
                this.id3v2.setAlbum(value);
            } catch (FieldDataInvalidException ex) {
                throw new Id3ProxyDataException();
            }
        }
    }

    @Override
    public void setYear(String value) throws Id3ProxyDataException {
        if (this.vers == ID3Version.V1 || this.vers == ID3Version.ALL) {
            this.id3v1.setYear(value);
        }
        if (this.vers == ID3Version.V2 || this.vers == ID3Version.ALL) {
            try {
                this.id3v2.setYear(value);
            } catch (FieldDataInvalidException ex) {
                throw new Id3ProxyDataException();
            }
        }
    }

    @Override
    public void setGenre(String value) throws Id3ProxyDataException {
        if (this.vers == ID3Version.V1 || this.vers == ID3Version.ALL) {
            this.id3v1.setGenre(value);
        }
        if (this.vers == ID3Version.V2 || this.vers == ID3Version.ALL) {
            try {
                this.id3v2.setGenre(value);
            } catch (FieldDataInvalidException ex) {
                throw new Id3ProxyDataException();
            }
        }
    }

    @Override
    public void setComment(String value) throws Id3ProxyDataException {
        if (this.vers == ID3Version.V1 || this.vers == ID3Version.ALL) {
            this.id3v1.setComment(value);
        }
        if (this.vers == ID3Version.V2 || this.vers == ID3Version.ALL) {
            try {
                this.id3v2.setComment(value);
            } catch (FieldDataInvalidException ex) {
                throw new Id3ProxyDataException();
            }
        }
    }

    @Override
    public void setDiscNo(String value) throws Id3ProxyDataException {
        try {
            setTagFrame(value, ID3v24Frames.FRAME_ID_SET);
        } catch (FieldDataInvalidException ex) {
            throw new Id3ProxyDataException();
        }
    }

    @Override
    public void setAlbumArtist(String value) throws Id3ProxyDataException {
        try {
            setTagFrame(value, ID3v24Frames.FRAME_ID_ACCOMPANIMENT);
        } catch (FieldDataInvalidException ex) {
            throw new Id3ProxyDataException();
        }
    }

    @Override
    public void setComposer(String value) throws Id3ProxyDataException {
        try {
            setTagFrame(value, ID3v24Frames.FRAME_ID_COMPOSER);
        } catch (FieldDataInvalidException ex) {
            throw new Id3ProxyDataException();
        }
    }

    @Override
    public void setPublisher(String value) throws Id3ProxyDataException {
        try {
            setTagFrame(value, ID3v24Frames.FRAME_ID_PUBLISHER);
        } catch (FieldDataInvalidException ex) {
            throw new Id3ProxyDataException();
        }
    }

    @Override
    public void setOrigArtist(String value) throws Id3ProxyDataException {
        try {
            setTagFrame(value, ID3v24Frames.FRAME_ID_ORIGARTIST);
        } catch (FieldDataInvalidException ex) {
            throw new Id3ProxyDataException();
        }
    }

    @Override
    public void setCopyright(String value) throws Id3ProxyDataException {
        try {
            setTagFrame(value, ID3v24Frames.FRAME_ID_COPYRIGHTINFO);
        } catch (FieldDataInvalidException ex) {
            throw new Id3ProxyDataException();
        }
    }

    @Override
    public void setURL(String value) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void setEncoder(String value) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void setBPM(String value) throws Id3ProxyDataException {
        try {
            setTagFrame(value, ID3v24Frames.FRAME_ID_BPM);
        } catch (FieldDataInvalidException ex) {
            throw new Id3ProxyDataException();
        }
    }

    /**
     *
     * @param value
     * @throws Id3ProxyDataException
     */
    @Override
    public void setCoverArt(String value) throws Id3ProxyDataException {
        RandomAccessFile imgFile;
        try {
            imgFile = new RandomAccessFile(new File(value), "r");
            byte[] imgData = new byte[(int) imgFile.length()];
            imgFile.read(imgData);

            String mimeType = "image/" + value.substring(value.lastIndexOf(".") + 1).toLowerCase();
            if (mimeType.endsWith("jpeg")) {
                mimeType = "image/jpg";
            }
            this.id3v2.add(id3v2.createArtworkField(imgData, mimeType));
        } catch (FieldDataInvalidException ex) {
            throw new Id3ProxyDataException("Album Art: " + value);
        } catch (FileNotFoundException ex) {
            throw new Id3ProxyDataException("Album Art Not Found: " + value);
        } catch (IOException ex) {
            throw new Id3ProxyDataException("Album Art cannot be read: " + value);
        }
    }

    /**
     *
     * @throws Id3ProxyException
     */
    @Override
    public void save() throws Id3ProxyException {
        try {
            mp3.setID3v1Tag(this.id3v1);
            mp3.setID3v2Tag(this.id3v2);
            mp3.commit();
        } catch (CannotWriteException ex) {
            throw new Id3ProxyException("Cannot Write " + file.getPath());
        }
    }

    /**
     *
     * @return
     */
    @Override
    public String getLibName() {
        return "JAudioTagger-1.0.9";
    }

    /**
     *
     * @param value
     * @param identifier
     * @throws FieldDataInvalidException
     */
    protected void setTagFrame(String value, String identifier) throws FieldDataInvalidException {
        if (this.vers == ID3Version.V2 || this.vers == ID3Version.ALL) {
            AbstractID3v2Frame frame = id3v2.getFirstField(identifier);
            if (frame == null) {
                frame = new ID3v24Frame(identifier);
            }

            AbstractFrameBodyTextInfo textBody = (AbstractFrameBodyTextInfo) frame.getBody();
            textBody.setText(value);

            frame.setBody(textBody);

            this.id3v2.set(frame);
        }
    }

    /**
     *
     * @param value
     * @throws Id3ProxyDataException
     * @throws Id3ProxyUnsupportedException
     */
    @Override
    public void setGrouping(String value) throws Id3ProxyDataException, Id3ProxyUnsupportedException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     *
     * @param value
     * @throws Id3ProxyDataException
     * @throws Id3ProxyUnsupportedException
     */
    @Override
    public void setIsCompilation(boolean value) throws Id3ProxyDataException, Id3ProxyUnsupportedException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     *
     * @return
     */
    @Override
    public String[] getSupportedExt() {
        String[] ext = {"mp3", "ogg"};
        return ext;
    }
}
